package com.xuehuitao.imagetoexcel.fileService;

import com.xuehuitao.imagetoexcel.dto.ConvertResult;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

@Service
public class ImageToExcelConverter {
    private static final Map<Integer, XSSFCellStyle> styleCache = new HashMap<>();

    private static final Logger logger = LoggerFactory.getLogger(ImageToExcelConverter.class);

    public String convertImageToExcel(String imagePath, int cellSize) {
        // 清空样式缓存
        styleCache.clear();
        //生成一个随机数
        String fileName = String.valueOf(System.currentTimeMillis());

        String outputExcelPath = "D:/download/data/" + fileName + ".xlsx";
        try {
            logger.info("开始转换图片为Excel文件...");
            // 读取图片文件
            BufferedImage image = ImageIO.read(new File(imagePath));

            // 创建一个新的Excel工作簿和工作表
            Workbook workbook = new XSSFWorkbook();
            Sheet sheet = workbook.createSheet("Image to Excel");

            int widthInCells = (image.getWidth() + cellSize - 1) / cellSize;
            int heightInCells = (image.getHeight() + cellSize - 1) / cellSize;

            // 遍历图片像素并设置单元格颜色
            for (int cy = 0; cy < heightInCells; cy++) {
                Row row = sheet.createRow(cy);

                for (int cx = 0; cx < widthInCells; cx++) {
                    Cell cell = row.createCell(cx);
                    cell.setCellValue("");

                    // 获取区域平均颜色
                    int rgb = getAverageRGB(image, cx * cellSize, cy * cellSize, cellSize);

                    // 获取或创建样式
                    //XSSFCellStyle cellStyle = getOrCreateStyle(workbook, rgb);
                    XSSFCellStyle cellStyle = styleCache.get(rgb);
                    if (cellStyle == null) {
                        cellStyle = getOrCreateStyle(workbook, rgb);
                        styleCache.put(rgb, cellStyle);
                    }
                    // 设置样式到单元格
                    cell.setCellStyle(cellStyle);
                }
            }

            // 自动调整列宽
            for (int i = 0; i < widthInCells; i++) {
                sheet.setColumnWidth(i, cellSize * 256); // 列宽单位是1/256字符宽度
            }

            // 保存Excel文件
            try (FileOutputStream fileOut = new FileOutputStream(outputExcelPath)) {
                workbook.write(fileOut);
            }

            logger.info("Excel文件已生成：" + outputExcelPath);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return outputExcelPath;
    }


    private static int getAverageRGB(BufferedImage image, int startX, int startY, int cellSize) {
        long sumRed = 0, sumGreen = 0, sumBlue = 0;
        int count = 0;

        for (int y = startY; y < Math.min(startY + cellSize, image.getHeight()); y++) {
            for (int x = startX; x < Math.min(startX + cellSize, image.getWidth()); x++) {
                int rgb = image.getRGB(x, y);
                sumRed += (rgb >> 16) & 0xFF;
                sumGreen += (rgb >> 8) & 0xFF;
                sumBlue += rgb & 0xFF;
                count++;
            }
        }

        return (int) (((sumRed / count) << 16) | ((sumGreen / count) << 8) | (sumBlue / count));
    }

    private XSSFCellStyle getOrCreateStyle(Workbook workbook, int rgb) {
        return styleCache.computeIfAbsent(rgb, key -> {
            XSSFWorkbook xssfWorkbook = (XSSFWorkbook) workbook;
            XSSFColor color = new XSSFColor(new byte[]{
                    (byte) ((key >> 16) & 0xFF),
                    (byte) ((key >> 8) & 0xFF),
                    (byte) (key & 0xFF)
            }, null);

            XSSFCellStyle style = (XSSFCellStyle) xssfWorkbook.createCellStyle();
            style.setFillForegroundColor(color);
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            return style;
        });
    }

    private static final ConcurrentHashMap<Integer, XSSFCellStyle> styleCache1 = new ConcurrentHashMap<>();

    /**
     * 多线程处理
     * @param imagePath
     * @param cellSize
     * @return
     */

    public ConvertResult convertImageToExcelNew(String imagePath, int cellSize) {
        ConvertResult convertResult = new ConvertResult();
        styleCache1.clear();
        String fileName = String.valueOf(System.currentTimeMillis());
        String outputExcelPath = "D:/download/data/" + fileName + ".xlsx";

        try {
            // 确保输出目录存在
            File outputFile = new File(outputExcelPath);
            if (!outputFile.getParentFile().exists()) {
                outputFile.getParentFile().mkdirs();
            }

            // 加载图片
            BufferedImage image = ImageIO.read(new File(imagePath));
            int widthInCells = (image.getWidth() + cellSize - 1) / cellSize;
            int heightInCells = (image.getHeight() + cellSize - 1) / cellSize;
            if (widthInCells >= 300 || heightInCells >= 300){
                convertResult.setErrorMessage("当前文件不支持以"+cellSize+"这个大小进行生成excel,清重新选择大小");
                return convertResult;
            }

            // 使用 SXSSF 流式写入模型
            Workbook workbook = new SXSSFWorkbook(100);
            Sheet sheet = workbook.createSheet("Image to Excel");

            // 多线程预计算所有单元格的 RGB 值
            int[][] rgbData = new int[heightInCells][widthInCells];
            int threadCount = Math.min(Runtime.getRuntime().availableProcessors(), 8); // 最多8个线程
            ExecutorService executor = Executors.newFixedThreadPool(threadCount);

            int rowsPerTask = Math.max(1, heightInCells / Runtime.getRuntime().availableProcessors());
            int totalTasks = (int) Math.ceil((double) heightInCells / rowsPerTask);
            CountDownLatch latch = new CountDownLatch(totalTasks);

            for (int startCy = 0; startCy < heightInCells; startCy += rowsPerTask) {
                final int blockStart = startCy;
                final int blockEnd = Math.min(startCy + rowsPerTask, heightInCells);
                executor.submit(() -> {
                    try {
                        logger.debug("线程开始处理: {} ~ {}", blockStart, blockEnd);
                        for (int cy = blockStart; cy < blockEnd; cy++) {
                            for (int cx = 0; cx < widthInCells; cx++) {
                                rgbData[cy][cx] = getAverageRGB2(image, cx * cellSize, cy * cellSize, cellSize);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("线程执行失败，blockStart={}, blockEnd={}", blockStart, blockEnd, e);
                    } finally {
                        latch.countDown();
                    }
                    logger.debug("线程结束处理: {} ~ {}", blockStart, blockEnd);
                });
            }

            // 等待所有线程完成
            boolean finished = latch.await(30, TimeUnit.SECONDS);
            if (!finished) {
                logger.warn("部分任务未在规定时间内完成");
            }
            executor.shutdown();
            try {
                if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
            }
            logger.info("一共需要处理: {}行", heightInCells);
            // 主线程写入 Excel 数据
            for (int cy = 0; cy < heightInCells; cy++) {
                //每50行打印一次
                if (cy % 50 == 0 && cy > 0) {
                    logger.info("已处理: {}行", cy);
                }
                Row row = sheet.createRow(cy);
                for (int cx = 0; cx < widthInCells; cx++) {
                    Cell cell = row.createCell(cx);
                    XSSFCellStyle cellStyle = getOrComputeStyle1(workbook, rgbData[cy][cx]);
                    cell.setCellStyle(cellStyle);
                }

                // 每 50 行刷新一次内存，释放资源
                if (cy % 50 == 0 && cy > 0) {
                    ((SXSSFSheet) sheet).flushRows(cy);
                }
            }

            // 设置列宽
            for (int i = 0; i < widthInCells; i++) {
                sheet.setColumnWidth(i, cellSize * 256);
            }

            // 写出文件
            try (FileOutputStream fileOut = new FileOutputStream(outputExcelPath)) {
                workbook.write(fileOut);
            }

            logger.info("Excel文件已生成：{}", outputExcelPath);
            convertResult.setFileUrl(outputExcelPath);
            return convertResult;

        } catch (Exception e) {
            logger.error("转换图片为Excel失败", e);
            throw new RuntimeException("转换图片为Excel失败", e);
        }
    }

    /**
     * 计算指定区域的平均 RGB 颜色值
     */
    private int getAverageRGB1(BufferedImage image, int startX, int startY, int cellSize) {
        long sumRed = 0, sumGreen = 0, sumBlue = 0;
        int count = 0;

        for (int y = startY; y < Math.min(startY + cellSize, image.getHeight()); y++) {
            for (int x = startX; x < Math.min(startX + cellSize, image.getWidth()); x++) {
                int rgb = image.getRGB(x, y);
                sumRed += (rgb >> 16) & 0xFF;
                sumGreen += (rgb >> 8) & 0xFF;
                sumBlue += rgb & 0xFF;
                count++;
            }
        }

        return (int) (((sumRed / count) << 16) | ((sumGreen / count) << 8) | (sumBlue / count));
    }

    /**
     * 边界问题
     * @param image
     * @param startX
     * @param startY
     * @param cellSize
     * @return
     */
    private int getAverageRGB2(BufferedImage image, int startX, int startY, int cellSize) {
        long sumRed = 0, sumGreen = 0, sumBlue = 0;
        int count = 0;

        int endX = Math.min(startX + cellSize, image.getWidth());
        int endY = Math.min(startY + cellSize, image.getHeight());

        for (int y = startY; y < endY; y++) {
            for (int x = startX; x < endX; x++) {
                int rgb = image.getRGB(x, y);
                sumRed += (rgb >> 16) & 0xFF;
                sumGreen += (rgb >> 8) & 0xFF;
                sumBlue += rgb & 0xFF;
                count++;
            }
        }

        if (count == 0) {
            return 0; // 默认黑色
        }

        return (int) (((sumRed / count) << 16) | ((sumGreen / count) << 8) | (sumBlue / count));
    }

    /**
     * 获取或创建样式（线程安全）
     */
    private XSSFCellStyle getOrComputeStyle1(Workbook workbook, int rgb) {
        return styleCache1.computeIfAbsent(rgb, key -> {
            // 获取底层真正的 XSSFWorkbook
            XSSFWorkbook xssfWorkbook = ((SXSSFWorkbook) workbook).getXSSFWorkbook();

            XSSFColor color = new XSSFColor(new byte[]{
                    (byte) ((key >> 16) & 0xFF),
                    (byte) ((key >> 8) & 0xFF),
                    (byte) (key & 0xFF)
            }, null);

            XSSFCellStyle style = (XSSFCellStyle) xssfWorkbook.createCellStyle();
            style.setFillForegroundColor(color);
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            return style;
        });
    }
}
